﻿namespace USElections.NewsFeeds.Model
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Diagnostics;
    using System.IO;
    using System.Linq;
    using System.ServiceModel.Syndication;
    using System.Windows.Data;
    using System.Xml;
    using System.Xml.Linq;
    using AgFx;
    using USElections.Utils;
    
    /// <summary>
    /// RssFeed class.
    /// </summary>
    [CachePolicy(CachePolicy.CacheThenRefresh, 60 * 60 * 24)]
    public class RssFeedModel : ModelItemBase<RssFeedLoadContext>
    {
        #region Fields
        private IEnumerable<SyndicationItem> originalItems = new Collection<SyndicationItem>();
        private string name = "-"; // placeholder.
        #endregion

        #region Constructor
        /// <summary>
        /// Initializes a new instance of the RssFeed class.
        /// </summary>
        public RssFeedModel()
        {
        }

        /// <summary>
        /// Initializes a new instance of the RssFeed class.
        /// </summary>
        /// <param name="name">Name of the feed.</param>
        /// <param name="uri">Rss Feed Uri.</param>
        public RssFeedModel(string name, string uri)
            : base(new RssFeedLoadContext(name, uri))
        {
            this.Name = name;
            this.Uri = uri;
        }
        #endregion

        #region Public properties
        /// <summary>
        /// Gets or sets the name of the feed.
        /// </summary>
        public string Name
        {
            get
            {
                return this.name;
            }

            set
            {
                this.name = value;
                RaisePropertyChanged("Name");
            }
        }

        /// <summary>
        /// Gets or sets the Uri of the feed.
        /// </summary>
        public string Uri { get; set; }

        /// <summary>
        /// Gets or sets the underlying items.
        /// </summary>
        [DependentOnProperty(PrimaryPropertyName = "OriginalItems")]
        public PagedCollectionView Items
        {
            get
            {
                return new PagedCollectionView(this.OriginalItems);
            }
        }

        public IEnumerable<SyndicationItem> OriginalItems
        {
            get
            {
                return this.originalItems;
            }
            set
            {
                this.originalItems = value;
                RaisePropertyChanged("OriginalItems");
            }
        }
        #endregion

        #region Public methods
        #endregion

        #region Private methods
        /// <summary>
        /// Parse the XML data.
        /// </summary>
        /// <param name="xml">The input xml.</param>
        /// <returns>A collection of Syndication items.</returns>
        private static IEnumerable<SyndicationItem> ParseXmlData(string xml)
        {
            if (string.IsNullOrEmpty(xml))
            {
                return null;
            }

            try
            {
                StringReader stringReader = new StringReader(xml);
                XmlReader xmlReader = XmlReader.Create(stringReader);

                // some ugly code to make the WashingtonPost and CNN work.
                XElement xe = XElement.Load(xmlReader, LoadOptions.None);

                foreach (var a in xe.Descendants().Where(x => x.Name == "pubDate"))
                {
                    DateTime correct = DateTime.Now;

                    ////Debug.WriteLine("before: " + a.Value);

                    DateTime newValue;

                    if (DateTime.TryParse(a.Value, out newValue))
                    {
                        correct = newValue;
                    }

                    ////Wed, 08 Feb 2012 23:06:41 GMT
                    a.Value = correct.ToString("ddd, dd MMM yyyy HH:mm:ss")  + " GMT";

                    ////Debug.WriteLine("after: " + a.Value);
                }

                var abc = xe.ToString();
                StringReader sr = new StringReader(abc);
                XmlReader xr = XmlReader.Create(sr);
                /* end of ugly code */

                SyndicationFeed synfeed = SyndicationFeed.Load(xr);

                return synfeed.Items;
            }
            catch (Exception ex)
            {
                Debug.WriteLine("WARNING: Failed to parse RSS feed: " + ex.Message);
            }

            return null;
        }
        #endregion

        #region internal classes
        /// <summary>
        /// VotesDataLoader class.
        /// </summary>
        public class RssFeedDataLoader : IDataLoader<RssFeedLoadContext>
        {
            #region Public methods
            public object Deserialize(RssFeedLoadContext loadContext, Type objectType, System.IO.Stream stream)
            {
                if (loadContext == null)
                {
                    return null;
                }

                StreamReader reader = new StreamReader(stream);
                string rssfeed = reader.ReadToEnd();

                RssFeedModel feed = new RssFeedModel(loadContext.Name, loadContext.Uri);

                if (!string.IsNullOrEmpty(rssfeed))
                {
                    IEnumerable<SyndicationItem> items = RssFeedModel.ParseXmlData(rssfeed);

                    if (items != null)
                    {
                        feed.OriginalItems = items;
                    }
                }

                return feed;
            }

            public LoadRequest GetLoadRequest(RssFeedLoadContext loadContext, Type objectType)
            {
                return new MyWebLoadRequest(loadContext, new Uri(loadContext.Uri));
            }
            #endregion
        }
        #endregion
    }
}